"""
Documentation for the main webpy app module.
Please read Project_Thesis.pdf for information on the background, motivation and implementation of this project

Created on May 17, 2011
Web py University of Edinburgh DSc Masters project
@author: Stelios Voutsinas
"""

import matplotlib
matplotlib.use('Agg')
import sys, os
abspath = os.path.dirname(__file__)
sys.path.append(abspath)
os.chdir(abspath)
import urllib2
import urllib
import StringIO
import time
import html_functions
import xml_parser
import xml.dom.minidom
import atpy
import json
import ast
import re
import operator  
import numpy
from config import *
from file_handler import File_handler
from matplotlib_plots import Matplotlib_plots
from misc import clear_temp_folder


### Set to false when launching
web.config.debug = True 

### Query form object
my_form = web.form.Form(web.form.Textarea('textfield',web.form.notnull,row=200,cols=30, class_='textfield', id='textfield',description=''),web.form.Hidden(name='tap_endpoint',id='tap_endpoint'))

### Render URLs
urls = ('/', 'index','/save_as_vot','save_as_vot','/save_as_fits','save_as_fits','/save_as_html','save_as_html','/viewer','viewer','/send_email','send_email', '/data_tables_processing','data_tables_processing')
render = web.template.render('templates/')

### Testing for apache production env
app = web.application(urls, globals(), autoreload=False)
application = app.wsgifunc()


def change_destruction_time(url,new_time):
    """ 
    Change the destruction time for a TAP job

    ATTENTION: Currently unused in this version
    
    @param url: The URL for the TAP job to destroy
    @param new_time : The current time to set for the destruction of the TAP job
    """
    
    f = ''
    try:
        params = urllib.urlencode({'DESTRUCTION' : new_time}) 
        url = url+'/destruction'
        req = urllib2.Request(url, params)
        f = urllib2.urlopen(req)
        f.close()
    except IOError:
        if f!='':
            f.close()
        print "A network connection error occurred"
 
 



def generate_form_data(registry):
    """
    Fetch array of available TAP endpoints from the input registry. Uses XQuery, and returns a tuple of web.form.Checkbox objects, to be added to the tap endpoint selection form
    
    @param registry: A string containin the Registry URL
    @return: An tuple containing the registry endpoints as web.checkbox elements
    """

    query = """
    declare namespace ri='http://www.ivoa.net/xml/RegistryInterface/v1.0';
    for $x in //ri:Resource
    where $x/capability[@standardID='ivo://ivoa.net/std/TAP']
    and $x/@status='active'
    return $x/capability[@standardID='ivo://ivoa.net/std/TAP']/interface/accessURL
    """

  
    form_data=[]
    f=''
    try:
        params = urllib.urlencode({'performquery' : 'true', 'ResourceXQuery' : query}) 
        req = urllib2.Request(registry, params)
        f = urllib2.urlopen(req)
        dom = xml.dom.minidom.parseString(f.read())
        dom_results=dom.getElementsByTagName("accessURL")
        for i in dom_results:
            form_data.append(web.form.Checkbox(xml_parser.getText(i)))
        f.close()
    except Exception as e:
        if f!='':
            f.close()
        print "A network connection error occurred"
        print e
        return ""
    if form_data==[]:
        return ""
    else:
        return tuple(form_data)






def generate_endpoint_from_list(endpnt_list, prefixes):
    """
    Takes an list of TAP endpoint URLs separated by a double space, and generates a merged TAP service from the OGSDA-DAI TAP factory(global tap_factory variable)
           
    @param endpnt_lits: A list of available TAP endpoints as strings
    @param prefixes: A list of prefixes as a json object, from which we extract URL & name and submit to the Registry
    @return: A string with the new URL to be used by the client
    """
    
    final_lst = ""
    result=""
    urls = endpnt_list.split('  ')
    response = ''
    
    if len(urls)==1:
        result = urls[0]+'/'
    else:     
        prfxs = json.loads(prefixes)
        for endpoint in prfxs:
            url = endpoint['name']
            prefix = endpoint['value']
            if prefix == "":
                temp = url.split('//')[1]
                tap_index = 0
                tap_index = max(temp.rfind('/TAP'),temp.rfind('/tap'),temp.rfind('/Tap'))
                if (tap_index <0):
                    tap_index = len(temp)-1
                endpoint = temp[0:tap_index]
                endpoint = endpoint.replace('/','_')
                endpoint = endpoint.replace('-','_')
                endpoint = endpoint.replace('.','_')
            else:
                endpoint = prefix    
            metadata_url = ""
            if url.rfind('heidelberg')>0:
                metadata_url = 'http://dc.zah.uni-heidelberg.de/__system__/tap/run/tableMetadata'
            elif url.rfind('voparis-srv.obspm')>0:
                metadata_url =  url + "/VOSI/tables"
            else:
                metadata_url = url[0:max(url.rfind('/TAP'),url.rfind('/tap'),url.rfind('/Tap'),0)]+'/VOSI/tables'
            final_lst+= endpoint +"="+ url+'/sync '+ metadata_url +" \n"    
        headers = {"Content-type": "text/plain"}
        try:
            req = urllib2.Request(tap_factory, final_lst, headers)
            response = urllib2.urlopen(req)
            result = response.read()+'/TAP/' 
            response.close()
        except IOError:
            if response!='':
                response.close()
            result = "" 
            print "Could not generate the TAP endpoint from the TAP factory. IOError"  
    print result
    return result






def fetch_metadata(tap_endpoint):
    """
    Takes a TAP endpoint URL, and generates the table metadata. This is done by reading and parsing the XML table information using the xml_dom.minidom library and the xml_parser module
    
    @param tap_endpoint: A string with the TAP endpoint
    @return: HTML content with the metadata for the given URL
    """
    
    return_str = ''
    f = ''
    try:
        f = urllib.urlopen(tap_endpoint)
        dom_str = f.read()
        dom = xml.dom.minidom.parseString(dom_str)
        return_str = xml_parser.handleXML(dom)
        f.close()
    except Exception:
        if f!='':
            f.close()
        return_str =  "" 	 
    return return_str




def get_async_results(url, URI):
    """
    Open the given url and URI and read/return the result 

    @param url: A URL string to open
    @param URI: A URI string to attach to the URL request
    @return: The result of the HTTP request sent to the URI of the URL
    """
    
    res = ''
    f = ''
    try:
        req = urllib2.Request(url+URI)
        f = urllib2.urlopen(req)
        res =  f.read()
        f.close()
    except IOError:
        if f!='':
            f.close()
        print "A network connection error occurred"
    return res





def start_async_loop(url):
    """
    Takes a TAP url and starts a loop that checks the phase URI and returns the results when completed. The loop is repeated every [delay=3] seconds

    @param url: A URL string to be used
    @return: A Votable with the results of a TAP job, or '' if error
    """
    
    ### For debugging purposes use:
    max_size_exceeded = False 
    f = ""
    return_vot = ''
    try:
        while True:
            res = get_async_results(url,'/phase')
            if res=='COMPLETED':       
                req = urllib2.Request(url + '/results/result')
                f = urllib2.urlopen(req)
                f.read(MAX_FILE_SIZE) #100Mb = 104,857,600
                if len(f.read())>0:
                    max_size_exceeded = True
                if not max_size_exceeded:
                    return_vot = atpy.Table(url + '/results/result', type='vo')
                else:
                    return_vot = "MAX_ERROR" 
                break
            elif res=='ERROR' or res== '':
                return return_vot
            time.sleep(delay)
    except Exception as e:
        print e
        if f != "":
            f.close()
        return_vot = ''
    return return_vot    

        




def print_save_HTML_table_info(pathname):
    """
    Generates HTML content for HTML table save button
        
    @param tbl: A table with the results of a query as a JSON, escaped array
    @return: The HTML content with a save as button
    """
        

    result = '<div id="save_as"><form name="save_as_html" action="save_as_html" method="post"> <input type="hidden" name="pathname" value ="' 
    result += pathname + '"/><input type="submit" class ="save_button" value="Save as HTML" /></form></div>'
    return result
    
    




def print_save_VOTable_info(pathname):    
    """
    Generates HTML content for VOTable save button    

    @param vot: A table with the results of a query as a JSON, escaped array
    @return: The HTML content with a save as button
    """

    result = '<div id="save_as"><form name="save_as_vot" action="save_as_vot" method="post"> <input type="hidden" name="pathname" value ="' 
    result += pathname + '"/><input type="submit" class ="save_button" value="Save as Votable" /></form></div>'
    return result





def print_save_Fits_info(pathname):    
    """
    Generates HTML content for VOTable save button    

    @param vot: A table with the results of a query as a JSON, escaped array
    @return: The HTML content with a save as button
    """
    
    result = '<div id="save_as"><form name="save_as_fits" action="save_as_fits" method="post"> <input type="hidden" name="pathname" value ="' 
    result += pathname + '"/><input type="submit" class ="save_button" value="Save as Fits" /></form></div>'
    return result




def execute_async_query(url,mode_local,q):
    """
    Execute an ADQL query (q) against a TAP service (url + mode:sync|async)       
    Starts by submitting a request for an async query, then uses the received job URL to call start_async_loop, to receive the final query results 

    @param url: A string containing the TAP URL
    @param mode: sync or async to determine TAP mode of execution
    @param q: The ADQL Query to execute as string
    
    @return: Return a votable with the results, the TAP job ID and a temporary file path with the results stored on the server
    """    

    params = urllib.urlencode({'REQUEST': request, 'LANG': lang, 'FORMAT': result_format, 'QUERY' : q}) 
    full_url = url+mode_local

    votable = ''
    jobId= 'None'
    file_path=''
    try:
        #Submit job and get job id 
        req = urllib2.Request(full_url, params)
        opener = urllib2.build_opener()
        f = opener.open(req)
        jobId = f.url

        #Execute job and start loop requests for results
        req2 = urllib2.Request(jobId+'/phase',urllib.urlencode({'PHASE' : 'RUN'}))
        f2 = opener.open(req2)

        # Return results as a votable object
        votable = start_async_loop(jobId)
        
        if votable!='' and votable !="MAX_ERROR":
            clear_temp_folder()
            cols = list(votable.columns)
            lst = [cols,html_functions.escape_list(votable.data.tolist())]
            file_handle = File_handler()
            file_handle.create_temp_file()
            file_handle.write_to_temp_file(json.dumps(lst))
            file_handle.close_handle()    
            file_path = file_handle.pathname
    except IOError as e:
        print "A network connection error occurred"  
        print e
    return (votable,jobId,file_path)




    
    

def generate_JSON_from_query((votable,jobId,pathname),query="",tap_endpoint="",table_mode="static"):    
    """
    Generates HTML content for the results from an ADQL/TAP query    
    
    @param (votable,jobId,pathname): A tuple with the votable results, the jobID and the temporary file path
    @param query: The query that was executed
    @param tap_endpoint: The currently selected or generated TAP endpoint URL
    @return: The HTML content to be returned and asynchronously loaded on the users page after submitting a query
    """
    
    data_results = ""
    json_list = ""
    if votable == "MAX_ERROR":
        data_results = votable
        return data_results
    elif votable!='' and votable!= None and query != "" and tap_endpoint!="":
        if len(votable)>0:
            cols = list(votable.columns)
            row_list = votable.data.tolist() 
            content = '<div style="width:520px;height:40px;">' + print_save_VOTable_info(pathname) + print_save_HTML_table_info(pathname) + print_save_Fits_info(pathname) + '</div>'
            content += '<div style="clear:both;text-align:left;margin-left:50px;font-size:13px;">Query URL :  '+'<a href="'+jobId+'">'+ jobId + '</a>' + '</div><br>'
            content += '<form class="left" action="viewer" method="post" target="_new"><input type="hidden" name="query" value="'+ query +'"/><input type="hidden" name="cols" value="'+ html_functions.escape(json.dumps(cols)) +'"/><input type="hidden" name="filepath" id="temp_file" value="'+ pathname +'"/><input type="hidden" name="tap_endpoint" value="'+ tap_endpoint +'"/>'
            if table_mode == 'interactive':
                data_results = html_functions.escape_list(row_list)
                json_list = html_functions.escape(json.dumps(data_results))
                content += '<input type="hidden" id="hidden_json_results" name="results" value="' + json_list  + '" />'
            content += '<input type="submit" value="Launch in Viewer"/></form>'
            data_results = [cols]
            data_results.append([len(row_list)])
            data_results.append([content])
            return json.dumps(data_results)
        else:
            return json.dumps([])
    else:
        return data_results
    
    
    
def write_format_from_json(to_format,json_list):
    """
    Generates HTML to_format for a json array of data
    
    @param to_format: The format to which to transform a JSON list of data
    @param json_list: The source json list
    """
    
    html_array = json_list
    fields = html_array[0]
    data = html_array[1]
    t = atpy.Table()
    count = 0
    
    for val in fields:
        col_data = []
        for row in data:
            if(type(row[count])==unicode):
                col_data.append(numpy.str(row[count]))
            else:
                col_data.append(row[count])    
        count = count+1
        t.add_column(str(val),numpy.array(col_data),dtype=numpy.string_)
    d = StringIO.StringIO()
    t.write(d, type=to_format)
    result = d.getvalue()
    d.close()
    return result



    

class index:
    """
    Main index class, handles requests to the main page of the application.
    
    Accepts GET and POST requests. 
    Different parameters passed to the HTTP POST/GET functions determine the appropriate actions
    """
    
    def GET(self):
        """ 
        GET function 
        
        Handle an HTTP GET request, by rendering the index template and returning the HTML content
        """
        
        web.header("Content-Type", "text/html")
        form = my_form()
        if (use_config!='multitap'):
            return render.index_single_archive(form, "")
        else: 
            return render.index(form, "")

    def POST(self):
        """
        POST function 
        
        Handle an HTTP POST request
        Check input data: 
        If the user has selected to toggle the endpoints selection, a variable named endpoint_form is passed to the class,
        in which case the server should generate the list from the registry URL (registry_url variable)
        If tap endpoints variable is defined, generate a merged TAP endpoint from the OGSA-DAI factory
        If the data display variable is set to true, generate TAP metadata, and return this HTML content to the user
        Else, if the main form validates, execute an asynchronous query as requested from the user input
        """

        web.header('Content-Type', 'text/html')
        data = web.input(tap_endpoints="none",display="no",generated_tap="none",endpoint_form="",prefixes="",table_mode="static")
        form = my_form()       
        results_html_val = "No elements returned. Please check your query"
        metadata = ""
        tap_endpoint=""
        
        if data.endpoint_form=="display":
            if data.use_cached_endpoints != "1":
                endpoint_list = generate_form_data(registry_url)
            else :
                endpoint_list = cached_endpoints    
            if endpoint_list !="":
                tap_endpoint_form = web.form.Form(*endpoint_list)
                tap_endpoints = tap_endpoint_form()
                return tap_endpoints.render()
            else :
                return ""
                
        if data.tap_endpoints!="none":
            tap_endpoint=generate_endpoint_from_list(data.tap_endpoints.strip(),data.prefixes)            
            return tap_endpoint
        elif data.generated_tap!="none":
            tap_endpoint = data.generated_tap
        else:
            return "Please select from the list of TAP endpoints"
    
        if data.display == 'yes':
            if tap_endpoint!="":
                tap_index = max(tap_endpoint.rfind('/TAP'),tap_endpoint.rfind('/tap'),tap_endpoint.rfind('/Tap'))
                metadata_url = ""
                if tap_endpoint.rfind('heidelberg')>0:
                    metadata_url = 'http://dc.zah.uni-heidelberg.de/__system__/tap/run/tableMetadata'
                elif tap_endpoint.rfind('voparis-srv.obspm')>0:
                    metadata_url =  tap_endpoint+ "/VOSI/tables"
                else:    
                    metadata_url = tap_endpoint[0:tap_index] + "/VOSI/tables"
                metadata = fetch_metadata(metadata_url)
            else:
                return "No TAP endpoints selected"
            return metadata
        
        # Check for validation
        if tap_endpoint=="":
            return "Please select from the list of TAP endpoints before submitting a query"
        elif form.validates():
            # Get query from textfield and execute it / Get mode based on radio buttons
            query = form['textfield'].value.strip()

            if query.lower().rfind('top') > -1:
                if query.lower().rfind('order') < 0:
                    return "Query_Error"
            try:    
                results_html_val = generate_JSON_from_query(execute_async_query(tap_endpoint,mode_global,query),query,tap_endpoint,data.table_mode)            
            except Exception as e:
                print e
            if results_html_val !="":
                return results_html_val
            else:
                return "Error"
        else:
            return ERROR_HTML






class save_as_vot:
    """
    This class is called as a URL request, when a user wishes to save the results of a query as VOTable format

    """
  
    def GET(self):
        """
        GET function
        
        Raise error
        """
        
        raise web.seeother('/')
    
    def POST (self):
        """ 
        POST function
        
        Main Class functionality
        """

        web.header('Content-Type', 'application/x-votable+xml')
        data = web.input(pathname="")
        return_val = "No results returned"
        f = ""
        try:
            if data.pathname!="":
                f = open(data.pathname, 'r')
                strng = f.read()                
                return_val = write_format_from_json('vo',json.loads(strng))
                f.close()
        except IOError as e:
            if f!="":
                f.close()
            print "Exception caught.."
            print e
            return_val = ""
        return return_val    







class save_as_html:
    """ 
    This class is called as a URL request, when a user wishes to save the results of a query as HTML format

    """
   
    def GET(self):
        """ 
        GET function
        
        Raise error
        """
        
        raise web.seeother('/')

    def POST (self):
        """
        POST function
        
        Main Class functionality
        """
        
        web.header('Content-Type', 'multipart/form-data')
        data = web.input(pathname="")    
        return_val = "No results returned"
        f = ""
        try:
            if data.pathname!="":
                f = open(data.pathname, 'r')
                strng = f.read()                
                return_val = write_format_from_json('html',json.loads(strng))
                f.close()
        except IOError as e:
            if f!="":
                f.close()
            print "Exception caught.."
            print e
            return_val = "No results returned"
        return return_val    





class save_as_fits:
    """
    This class is called as a URL request, when a user wishes to save the results of a query as VOTable format

    """
  
    def GET(self):
        """
        GET function
        
        Raise error
        """
        
        raise web.seeother('/')
    
    def POST (self):
        """ 
        POST function
        
        Main Class functionality
        """

        web.header('Content-Type', 'application/fits')
        data = web.input(pathname="")
        return_val = "No results returned"
        f = ""
        try:
            if data.pathname!="":
                f = open(data.pathname, 'r')
                strng = f.read()                
                return_val = write_format_from_json('fits',json.loads(strng))
                f.close()
        except IOError as e:
            if f!="":
                f.close()
            print "Exception caught.."
            print e
            return_val = ""
        return return_val    






class viewer:
    """
    This class serves as an additional URL class, which takes a set of parameters, and allows users to create a plot based on the results of an ADQL/TAP query

    """

    def tryeval(self,val):
        try:
            val = ast.literal_eval(val)
        except ValueError:
            pass
        return val

    
    
    def GET(self):
        """ 
        GET function

        Return empty string
        """
        return ""        
        
        
    def POST (self):
        """ 
        POST function
        
        Main Class functionality
        """
        
        data = web.input(results="", cols="",query="",xaxis="",yaxis="",tap_endpoint="",filepath="",x_alias="",y_alias="", mode="interactive", plot_type="Scatter", bins="10")
        #result = ''
        return_value=''
        web.header('Content-Type', 'text/html')
        if ((data.xaxis != "" and data.yaxis!="" and data.x_alias!="" and data.y_alias!="" and data.plot_type=="Scatter") or (data.xaxis != "" and data.x_alias!="" and data.plot_type=="Histogram")):           
            if data.plot_type == "Scatter":
                #### EXPERIMENTAL DISTINCT
                new_query = 'SELECT ' + data.xaxis + ' as ' + data.x_alias + ',' + data.yaxis + ' as ' + data.y_alias + ' FROM ('+ data.query + ') AS query ORDER BY ' + data.x_alias
            else:
                new_query = 'SELECT ' + data.xaxis + ' as ' + data.x_alias + ' FROM ('+ data.query + ') AS query ORDER BY ' + data.x_alias
            votable,jobid, plot_file = execute_async_query(data.tap_endpoint,mode_global,new_query)
            
            if votable!='':            
                if len(votable)>0:
                    try:
                        data_to_list = votable.data.tolist()     
                        if data.plot_type=="Scatter":
                            if (type (data_to_list[0][0]) is str) or (type (data_to_list[0][1]) is str):
                                data_to_list = [map (self.tryeval,x) for x in data_to_list]
                                if (type (data_to_list[0][0]) is str) or (type (data_to_list[0][1]) is str):
                                    raise Exception
                        else: 
                            if (type (data_to_list[0][0]) is str):
                                data_to_list = [map (self.tryeval,x) for x in data_to_list]
                                if (type (data_to_list[0][0]) is str):
                                    raise Exception
                                
                        data_results = [list(votable.columns)]
                        data_results.append(data_to_list)
                        
                        if data.mode=="static":    
                            plot = Matplotlib_plots()
                            if data.plot_type=="Scatter":
                                plot_img = plot.generate_plot([[(x[0]) for x in data_to_list],[(x[1]) for x in data_to_list]],data.x_alias,data.y_alias,data.plot_type)
                            else :
                                plot_img = plot.generate_plot(data_to_list,data.x_alias,data.y_alias,data.plot_type, int(data.bins))  
                            data_results.append([plot_img])     
                        elif data.plot_type=="Histogram" :
                            plot = Matplotlib_plots()
                            data_results.append(plot.get_xy_values_for_hist(data_to_list, int(data.bins)))
                        return_value = json.dumps(data_results)        
                        
                    except Exception as e:
                        print "Error while processing the plot data"
                        print e
                        return_value = "<div style=\"color:red;margin-left:50px;font-size:12px\">Please enter correct column expressions</div>"   
            else : 
                return_value = "<div style=\"color:red;margin-left:50px;font-size:12px\">Please enter correct column expressions</div>"    
        table_cols = data.cols
        
        if table_cols == None or table_cols =="":
            table_cols = 0
        
        if return_value=='':
            return render.viewer(table_cols,'value="'+ data.query + '"','value="'+ data.tap_endpoint + '"','value="'+ data.filepath + '"', 'value="' + html_functions.escape(data.results) +'"')   
        else :
            return return_value






class send_email:
    """ 
    Class is used as an additional URL, which is called to send an email with the results of an ADQL/TAP query
    Expects input with the email, query, and TAP endpoint
    Uses Python's sendmail function

    """
     
    def GET(self):
        """
        GET function
        
        Raise error
        """
        raise web.seeother('/')


    def POST (self):
        """ 
        POST function
        
        Main Class functionality    
        """
        
        data = web.input(email="",query="",generated_tap="")
        if data.generated_tap !="" and data.email !="" and data.query !="":
            try:
                jobId = ""
                (votable,jobId,pathname) = execute_async_query(data.generated_tap,mode_global,data.query)
                if jobId =="":                
                    html = "<div style=\"color:red;margin-left:50px;\">Your ADQL request was not executed. Please check your query</div>"    
                else:
                    html = "The results of your query can be found at: " + jobId
                web.utils.sendmail(from_email, data.email, 'TAP Results', html, headers=({ 'Content-Type': 'text/html'})) #,attachments=[dict(filename="bug.xml", content=safestr(html_table))])
            except Exception as ex:
                print ex
            return ""   
        else:
            return ""        





class data_tables_processing:
    """
    URL Class to handle the processing of JQuery Datatable data
    """

    def search(self,values, rexp):
        """
        Float values are converted to strings with two decimals.
    
        ADVISORY: only use this function for final data to jsonify since
        data type is lost
    
        @param values: Values to cast
        @return: Formated values
        """
        for v in values:
            if re.search(rexp,str(v)):
                return True
        return False


    def process( self, lst, sidx, start=1, rows=10, sord="asc", echo=0, rexp=None, pfn=None ):
        """ 
        Process a request with JQuery Datatables data and parameters, and filter/return the appropriate data
        
        @param sidx : Column used to sort data
        @param start: Data chunck/page number (default: 1)
        @param rows : How many values do we display (default: 50)
        @param sord : Sort order, set to desc for reversed (default: True)
        @param echo : Simple internal iterator used by datatables for rendering
        @param rexp:  An expression to Filter the results by
        @param pfn  : Pickle file name -- only used if PICKLE = True (default: None)
        @return:None
        """
    
        try :
            data=lst[1]    
            sidx = int(sidx)
            start = int(start)
            rows = int(rows)
            echo = int(echo)
     
            # filter data (search case)
            if rexp != '': # rexp is casted to str
                data = filter(lambda x: self.search(x,str(rexp)), lst[1])
    
            r = True if sord == "desc" else False
            s = sorted( data, key=operator.itemgetter( sidx ), reverse=r )
    
            maxim = len(s)
            ff = start if start else 0
            tt = ff+rows if ff+rows < maxim else maxim
     
            # format floats to avoid X decimal
            f = s[ff:tt]
            # format data
            j = {
                "sEcho" : echo,
                "iTotalRecords" : str(len(s)),
                "iTotalDisplayRecords" : str(len(s)),
                "aaData": f
                }
            
        except Exception:
            print "Exception caught in function: data_tables_process"
            j = None
        return j


    def POST(self):
        """
        GET function
        
        Take a Pathname as a parameter, and generate the appropriate row data for use by jQuery Datatables
        """
        
        data = web.input(pathname="", iSortCol_0=0,iDisplayStart=1, iDisplayLength=10, sSortDir_0="asc", sEcho=0, sSearch=None, pfn=None )
        return_val = ""
        f = ''
        try:
            f = open(data.pathname, 'r')  
            val = f.read()    
            jsn = json.loads(val)
            sidx = data.iSortCol_0
            start = data.iDisplayStart
            rows = data.iDisplayLength
            sord = data.sSortDir_0
            echo = data.sEcho
            rexp = data.sSearch
            pfn = data.pfn
            return_val = json.dumps(data_tables_processing.process(self, jsn, sidx=sidx, start=start, rows=rows, sord=sord, echo=echo, rexp=rexp, pfn=pfn)) 
            f.close()
        except Exception as e:
            if f!='':
                f.close()
            print e
            return_val = ""
        return return_val
    



def is_test():
    """
    is_test() function
    
    Test whether the run is part of a test suite
    Run if not
    """
    if 'WEBPY_ENV' in os.environ:
        print "Initializing test"
        return os.environ['WEBPY_ENV'] == 'test'



if (not is_test()) and __name__ == "__main__": app.run()


